#include "wav_reader.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../base/file_io.h"

KWavReader::KWavReader()
{
	mpSamples = NULL;
}
KWavReader::~KWavReader()
{
	if (mpSamples)
		free(mpSamples);
}

bool KWavReader::OpenWavFile(const char *wav_file_name)
{
	int i;
	char obuff[80];
 
	WAV_HDR wav;
	CHUNK_HDR chk;
	int sflag;
	long int rmore;
	int wbuff_len;
 
	// open wav file 
	KFileReader fw(wav_file_name);
	if (!fw.IsFileOpen())
		return false;
 
	// read riff/wav header 
	if (!fw.Read(&wav, sizeof(WAV_HDR)))
		return false;

	// check format of header 
	for(i=0;i<4;i++) obuff[i] = wav.rID[i];
	obuff[4] = 0;
	if(strcmp(obuff,"RIFF")!=0)
		return false;

	for(i=0;i<4;i++) obuff[i] = wav.wID[i];
	obuff[4] = 0;
	if(strcmp(obuff,"WAVE")!=0)
		return false;

	for(i=0;i<3;i++) obuff[i] = wav.fId[i];
	obuff[3] = 0;
	if(strcmp(obuff,"fmt")!=0)
		return false;

	if(wav.wFormatTag!=1)
		return false;

	bool needBitConversion = true;
	if(wav.nBitsPerSample == 16)
		needBitConversion = false;
 
	// skip over any remaining portion of wav header 
	rmore = wav.pcm_header_len - (sizeof(WAV_HDR) - 20);
	if (!fw.Skip(rmore))
		return false;

	// read chunks until a 'data' chunk is found 
	sflag = 1;
	while(sflag!=0){

		// check attempts 
		if(sflag>10)
			return false;  // Too many chunks

		// read chunk header 
		if (!fw.Read(&chk, sizeof(CHUNK_HDR)))
			return false;

		// check chunk type 
		for(i=0;i<4;i++) obuff[i] = chk.dId[i];
		obuff[4] = 0;
		if(strcmp(obuff,"data")==0) break;
	  
		// skip over chunk 
		sflag++; 
		if (!fw.Skip(chk.dLen))
			return false;
	}
 
	// find length of remaining data 
	wbuff_len = chk.dLen;
 
	if (wav.nBitsPerSample % 8 != 0)
		return false;
	
	// find number of samples 
	mSampleCnt = chk.dLen;
	mSampleCnt /= wav.nBitsPerSample / 8;

	// allocate new buffers 
	mpSamples = (short*)malloc(wbuff_len);
	if(mpSamples==NULL)
		return false;

	bool result = false;
	// read signal data 
	if(!fw.Read(mpSamples, wbuff_len)) {
		free(mpSamples);
		mpSamples = NULL;	
	}
	else {
	
		if (needBitConversion) {
			unsigned int actual_buff_len = wbuff_len * 16 / wav.nBitsPerSample;
			short* pDestBuff = (short*)malloc(mSampleCnt * sizeof(short));
			unsigned char* pSrcBuff = (unsigned char*)mpSamples;
			unsigned int bytePerSamp = wav.nBitsPerSample / 8;
			for (unsigned int i = 0; i < mSampleCnt; ++i) {
				unsigned short currentSample = (pSrcBuff[bytePerSamp-1] << 8);
				if (bytePerSamp > 1)
					currentSample |= pSrcBuff[bytePerSamp - 2];
				else
					currentSample |= 0x00ff;
				pDestBuff[i] = (int)currentSample - 0x7fff;
				pSrcBuff += bytePerSamp;
			}
			free(mpSamples);
			mpSamples = pDestBuff;
		}
		
		if (wav.nChannels > 2) {
			// If there are more than two channels, it will be converted to stereo,
			// while mean the additional channels will be ignored.
			short* pDestBuff = (short*)malloc(mSampleCnt / wav.nChannels * 2);
			mSampleCnt = mSampleCnt / wav.nChannels * 2;
			short* pSrcBuff = (short*)mpSamples;
			for (unsigned int i = 0; i < mSampleCnt; i += 2) {
				pDestBuff[i] = pSrcBuff[i];
				pDestBuff[i + 1] = pSrcBuff[i + 1];
				pSrcBuff += wav.nChannels;
			}
			free(mpSamples);
			mpSamples = pDestBuff;
			wav.nChannels = 2;
		}
		
		mFreq = wav.nSamplesPerSec;
		mBitsPerSamp = 16;
		mChannelCnt = wav.nChannels;
		result = true;
	}

	return result;
}

bool KWavReader::IsOk() const
{
	return (mpSamples != NULL ? true : false);
}

bool KWavReader::IsStereo() const
{
	return (mChannelCnt == 2 ? true : false);
}

unsigned int KWavReader::GetSampleCnt() const
{
	return mSampleCnt;
}

const short* KWavReader::GetSamplePtr() const
{
	return mpSamples;
}

unsigned int KWavReader::GetFreq() const
{
	return mFreq;
}